#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <functional>
#include <sstream>
#include <fstream>

const static std::string base_sep = "\r\n";
const static std::string head_sep = ": ";
const static std::string space_sep = " ";
const static std::string httpversion = "HTTP/1.0";
const static std::string webrootdir = "wwwroot"; // web根目录
const static std::string suffix_sep = ".";
const static std::string defaultsuffix = ".default";
const static std::string homepages = "index.html";
const static std::string arg_sep = "?";

class HttpRequest {
private:
    
    // 解包一行的http报文
    std::string Decode(std::string& packagestream) {
        // 对数据逐渐的解包
        auto pos = packagestream.find(base_sep);
        if (pos == std::string::npos) return std::string();
        std::string line = packagestream.substr(0, pos);
        // 将line从packagestream中删除
        packagestream.erase(0, line.size() + base_sep.size());
        return line.empty() ? base_sep : line;
    }

    // 解析请求行
    void ParseRequestLine() {
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;

        ChangeGet();

        _path += _url;
        // 若当前请求的资源为根目录下的资源，直接让其跳转到对应的主页面
        if (_path.back() == '/') {
            _path += homepages;
        }

        // 获取对应资源文件的后缀
        auto pos = _path.rfind(suffix_sep);
        if (pos == std::string::npos) {
            _suffix = defaultsuffix;
        } else {
            _suffix = _path.substr(pos);
        }

    }

    // 解析请求报头
    void ParseHeaderLine() {
        for (auto& head : _req_headers) {
            // 现在从中取出数据
            auto pos = head.find(head_sep);
            if (pos == std::string::npos) continue;
            std::string k = head.substr(0, pos);
            std::string v = head.substr(pos + head_sep.size());
            if (k.empty() || v.empty()) continue;
            _headers_kv[k] = v;
        }
    }

    // 若当前的方法是 GET，则将后面的参数都给放到正文中
    void ChangeGet() {
        if (strcasecmp(_method.c_str(), "GET") == 0) {
            auto pos = _url.find(arg_sep);
            if (pos != std::string::npos) {
                std::string arg_str = _url.substr(pos + arg_sep.size());
                _url.resize(pos);
                arg_str += base_sep;
                _body_text += arg_str;
                // std::cout << "body text: " << _body_text << std::endl;
            }
        }
    }

public:
    HttpRequest() 
        : _blank_line(base_sep),
          _path(webrootdir)
    {}
    
    // 将请求报文进行反序列化
    void Deserialize(std::string& packagestream) {
        _req_line = Decode(packagestream);

        // 获取请求报头行
        do {
            std::string line = Decode(packagestream);
            if (line.empty()) break;
            else if (line == base_sep) break;
            _req_headers.push_back(line);

        } while (true);
    
        if (!packagestream.empty()) {
            _body_text = packagestream;
        }

        // 解析请求行和请求报头
        ParseRequestLine();
        ParseHeaderLine();
    }
    
    std::string Suffix() {
        return _suffix;
    }

    void GetRequestBody() {
        std::cout << "body text: " << _body_text << std::endl;
    }

    std::string Path() {
        return _path;
    }

    // DEBUG 打印解析出来的请求报文
    void PrintRequest() {
        // std::cout << _req_line << std::endl;
        // for (auto& head : _req_headers) {
        //     std::cout << head << std::endl;
        // }
        // std::cout << _blank_line;
        // std::cout << _body_text << std::endl;
        std::cout << _method << " " << _url << " " << _version << std::endl;
        for (auto& it : _headers_kv) {
            std::cout << it.first << head_sep << it.second << std::endl;
        }
        std::cout << _blank_line;
        std::cout << _body_text << std::endl;
    }

    ~HttpRequest() {}
private:
    std::string _req_line;                  // 请求行
    std::vector<std::string> _req_headers;  // 请求报头
    std::string _blank_line;                // 空行
    std::string _body_text;                 // 请求正文

    // 更将详细的解析，将如上的四种变量解析如下
    std::string _method;                                       // 获取方法：GET、POST、DELETE……
    std::string _url;                                          // 获取url
    std::string _version;                                      // http版本
    std::unordered_map<std::string, std::string> _headers_kv;  // 获取http报头

    std::string _path;              // 解析url中的资源路径
    std::string _suffix;            // 获取资源文件的后缀
};

class HttpResponce {
private:

public:
    HttpResponce()
        : _version(httpversion),
          _blank_line(base_sep)
    {}

    // 增加状态码以及对应的状态描述
    void AddStatuscode(int code, const std::string& desc) {
        _status_code = code;
        _desc_code = desc;
    }
    // 添加对应的响应报头
    void AddHead(const std::string& key, const std::string& value) {
        _headers_kv[key] = value;
    }
    // 添加对应的文本信息
    void AddContent(const std::string& content) {
        _body_text += content;
    }

    // 将报文序列化，然后返回
    std::string Serialize() {
        // 序列化状态行
        _status_line = _version + space_sep + std::to_string(_status_code) + space_sep + _desc_code + base_sep;
        
        for (auto& head : _headers_kv) {
            std::string line = head.first + head_sep + head.second + base_sep;
            _resp_headers.emplace_back(line);
        }
        
        // 序列换响应报头
        std::string responcepackage = _status_line;
        for (auto& line : _resp_headers) {
            responcepackage += line;
        }

        responcepackage += _blank_line;
        responcepackage += _body_text;
        return responcepackage;
    }

    ~HttpResponce() {}
private:
    std::string _status_line;               // 状态行
    std::vector<std::string> _resp_headers; // 响应报头
    std::string _blank_line;                // 空行
    std::string _body_text;                 // 正文

    // 真正的状态的
    std::string _version;                   // http版本
    int _status_code;                       // 状态码
    std::string _desc_code;                 // 状态描述
    std::unordered_map<std::string, std::string> _headers_kv; // 响应报头的键值和关键值
};


using func_t = std::function<HttpResponce(HttpRequest&)>;

class HttpServer {
private:
    // 从目录中读取信息
    std::string ReadContentFromRootdir(const std::string& path) {
        // 将文件以二进制形式打开

        // std::cout << "------------" << std::endl;

        std::ifstream in(path, std::ios::binary);
        if (!in.is_open()) return std::string();
        std::string content;

        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        content.resize(filesize);
        in.read((char*)content.c_str(), filesize);

        // std::cout << "xxxxxxxxxxxxxxxxx" << std::endl;


        in.close();
        return content;
    }

public:
    // 构造函数将状态码与状态描述  文件后缀与网页类型初始化
    HttpServer() {
        _code_to_desc[100] = "Continue";
        _code_to_desc[200] = "OK";
        _code_to_desc[201] = "Created";
        _code_to_desc[204] = "No Content";
        _code_to_desc[301] = "Moved Permanently";
        _code_to_desc[302] = "Found";
        _code_to_desc[304] = "Not Modified";
        _code_to_desc[400] = "Bad Request";
        _code_to_desc[401] = "Unauthorized";
        _code_to_desc[403] = "Forbidden";
        _code_to_desc[404] = "Not Found";
        _code_to_desc[500] = "Internal Server Error";
        _code_to_desc[502] = "Bad Gateway";
        _code_to_desc[503] = "Service Unavailable";

        _mini_type[".html"] = "text/html";
        _mini_type[".jpg"] = "image/jpeg";
        _mini_type[".png"] = "image/png";
        _mini_type[".default"] = "text/html";
    }

// #define TEST 1

    // 将数据进行转发
    std::string HttpServerHandler(std::string& reqstr) {
#ifdef TEST
        std::cout << "-----------------------------" << std::endl;
        std::cout << reqstr;

        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hello Linux, hello fans!</h1></html>";
        // Content-Length
        // return responsestr;

        return reqstr;
#else
        std::cout << "----------------------------------------" << std::endl;
        std::cout << reqstr << std::endl;
        
        // 将对应的请求报文给反序列化
        HttpRequest Req;
        Req.Deserialize(reqstr);
        // 将正文消息打印出来
        // Req.GetRequestBody();
        // 将消息打印出来
        // std::cout << content << std::endl;

        HttpResponce Resp;

        // 这里测试重定向 --> 进入的我的主页面
        if (Req.Path() == "wwwroot/redir") {
            // 301 表示永久重定向
            Resp.AddStatuscode(301, _code_to_desc[301]);
            std::string path = "https://blog.csdn.net/m0_74830524?spm=1000.2115.3001.5343";
            Resp.AddHead("Location", path);
            Resp.AddHead("Content-Type", defaultsuffix);

            return Resp.Serialize();
        }
        
        std::string content = ReadContentFromRootdir(Req.Path());

        if (content.empty()) {
            // 为空，为 404 not find
            if (!_service_list.count(Req.Path())) {
                Resp.AddStatuscode(404, _code_to_desc[404]);
                content = ReadContentFromRootdir("wwwroot/404.html");
                Resp.AddHead("Content-Length", std::to_string(content.size()));
                std::string suffix = Req.Suffix();
                Resp.AddHead("Content-Type", _mini_type[suffix]);
                Resp.AddHead("Set-Cookie", "username=zhangsan");
                Resp.AddContent(content);
            } else {
                // 存在我们则执行servicelist中的任务
                Resp = _service_list[Req.Path()](Req);
            }
        } else {
            // 正文内容存在，直接获取
            Resp.AddStatuscode(200, _code_to_desc[200]);
            Resp.AddHead("Content-Length", std::to_string(content.size()));
            Resp.AddHead("Content-Type", "text/html");
            Resp.AddContent(content);
        }


        return Resp.Serialize();
#endif
    }

    // 增加任务
    void AddService(const std::string& name, func_t service) {
        std::string servicename = webrootdir + name;
        _service_list[servicename] = service;
    }

    ~HttpServer() {}

private:
    std::unordered_map<int, std::string> _code_to_desc;         // 状态码和状态描述的映射
    std::unordered_map<std::string, std::string> _mini_type;    // 文件后缀与网页类型的映射
    std::unordered_map<std::string, func_t> _service_list;      // 任务类型的映射
};